package com.bjzh.bjzh.common.aspect;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.bjzh.bjzh.common.exception.RRException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;


@Aspect
@Component
@Slf4j
public class SignatureValidation {
    /**
     * 时间戳请求最小限制(30s)
     * 设置的越小，安全系数越高，但是要注意一定的容错性
     */
    private static final long MAX_REQUEST = 30 * 1000L;
    /**
     * 秘钥
     */
    private static final String SECRET = "123456789";

    /**
     * 验签切点(完整的找到设置的文件地址)
     */
    @Pointcut("execution(@com.bjzh.bjzh.common.aop.SignatureValidation * *(..))")
    private void verifyUserKey() {
    }

    /**
     * 开始验签
     */
    @Before("verifyUserKey()")
    public void doBasicProfiling() {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String token = request.getHeader("token");
        Map<String, String[]> parameterMap = request.getParameterMap();
        try {
            Boolean check = checkToken(token, parameterMap);
            if (!check) {
                // 自定义异常抛出（开发者自行换成自己的即可）
                throw new RRException("签名验证错误");
            }
        } catch (Throwable throwable) {
            // 自定义异常抛出（开发者自行换成自己的即可）
            throw new RRException("签名验证错误");
        }
    }

    /**
     * 校验token
     *
     * @param token     签名
     * @param timestamp 时间戳
     * @return 校验结果
     */
    private Boolean checkToken(String token, Map<String, String[]> map) {
        if (!StrUtil.isAllNotBlank(token)) {
            return false;
        }
        StringBuilder sb = new StringBuilder();
        sb.append(SECRET);
        TreeMap<String, String[]> sort = MapUtil.sort(map);
        for (String s : sort.keySet()) {
            sb.append(s).append(sort.get(s)[0]);
        }
        /**
        long now = System.currentTimeMillis();
        long time = Long.parseLong(timestamp);
        if (now - time > MAX_REQUEST) {
            log.error("时间戳已过期[{}][{}][{}]", now, time, (now - time));
            return false;
        }
         */
        String crypt = DigestUtil.md5Hex(sb.toString());
        return StrUtil.equals(crypt, token);
    }
}


